package com.ruoyi.framework.config;

import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.databind.ser.std.DateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.NonNull;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
import java.util.TimeZone;

/**
 * 程序注解配置
 *
 * @author ruoyi
 */
@SuppressWarnings({"Convert2Lambda", "Convert2Diamond"})
@Configuration
// 表示通过aop框架暴露该代理对象,AopContext能够访问
@EnableAspectJAutoProxy(exposeProxy = true)
// 指定要扫描的Mapper类的包的路径
@MapperScan("com.ruoyi.**.mapper")
public class ApplicationConfig {
    /**
     * 时区配置
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
    }


    /**
     * LocalDateTime转换器，用于转换RequestParam和PathVariable参数
     */
    @Bean
    public Converter<String, LocalDateTime> localDateTimeConverter() {
        // 这里不能使用lambda，否则出现类型转换错误
        return new Converter<String, LocalDateTime>() {
            @Override
            public LocalDateTime convert(@NonNull String source) {
                try {
                    return LocalDateTime.parse(source.trim(), DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
                } catch (DateTimeParseException e) {
                    throw new IllegalArgumentException(String.format("将“%s”转换为LocalDateTime类型失败，时间格式为“%s”", source, DatePattern.NORM_DATETIME_PATTERN), e);
                }
            }
        };
    }

    /**
     * LocalDate转换器，用于转换RequestParam和PathVariable参数
     */
    @Bean
    public Converter<String, LocalDate> localDateConverter() {
        // 这里不能使用lambda，否则出现类型转换错误
        return new Converter<String, LocalDate>() {
            @Override
            public LocalDate convert(@NonNull String source) {
                try {
                    return LocalDate.parse(source.trim(), DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN));
                } catch (DateTimeParseException e) {
                    throw new IllegalArgumentException(String.format("将“%s”转换为LocalDate类型失败，时间格式为“%s”", source, DatePattern.NORM_DATE_PATTERN), e);
                }
            }
        };
    }

    /**
     * LocalTime转换器，用于转换RequestParam和PathVariable参数
     */
    @Bean
    public Converter<String, LocalTime> localTimeConverter() {
        // 这里不能使用lambda，否则出现类型转换错误
        return new Converter<String, LocalTime>() {
            @Override
            public LocalTime convert(@NonNull String source) throws IllegalArgumentException {
                try {
                    return LocalTime.parse(source.trim(), DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN));
                } catch (DateTimeParseException e) {
                    throw new IllegalArgumentException(String.format("将“%s”转换为LocalTime类型失败，时间格式为“%s”", source, DatePattern.NORM_TIME_PATTERN), e);
                }
            }
        };
    }

    /**
     * Date转换器，用于转换RequestParam和PathVariable参数
     */
    @Bean
    public Converter<String, Date> dateConverter() {
        // 这里不能使用lambda，否则出现类型转换错误
        return new Converter<String, Date>() {
            @Override
            public Date convert(@NonNull String source) throws IllegalArgumentException {
                SimpleDateFormat format = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
                try {
                    return format.parse(source.trim());
                } catch (ParseException e) {
                    throw new IllegalArgumentException(String.format("将“%s”转换为Date类型失败，时间格式为“%s”", source, DatePattern.NORM_DATETIME_PATTERN), e);
                }
            }
        };
    }

    /**
     * LocalDateTime 转换器，用于转换返回结果中 LocalDateTime 类型字段
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer localDateTimeJackson2ObjectMapperBuilderCustomizer() {
        return builder -> builder.serializerByType(LocalDateTime.class,
                new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN))
        );
    }

    /**
     * LocalDate 转换器，用于转换返回结果中 LocalDate 类型字段
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer localDateJackson2ObjectMapperBuilderCustomizer() {
        return builder -> builder.serializerByType(LocalDate.class,
                new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN))
        );
    }

    /**
     * LocalTime 转换器，用于转换返回结果中 LocalTime 类型字段
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer localTimeJackson2ObjectMapperBuilderCustomizer() {
        return builder -> builder.serializerByType(LocalTime.class,
                new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN))
        );
    }

    /**
     * Date 转换器，用于转换返回结果中 Date 类型字段
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer dateJackson2ObjectMapperBuilderCustomizer() {
        SimpleDateFormat format = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
        return builder -> builder.serializerByType(Date.class,
                // false 不使用时间戳，使用对应格式时间
                new DateSerializer(false, format)
        );
    }

}
